/*
 * mpls.cc
 *
 *  Created on: May 17, 2011
 *      Author: Zhuruev Konstantin
 */

#include <stdio.h>
#include <string.h>
#include <omnetpp.h>


class Ingress_Router : public cSimpleModule
{
  private:
    simtime_t timeout;  // timeout
    cMessage *timeoutEvent;  // holds pointer to the timeout self-message
    int seq;  // message sequence number
    cMessage *message;  // message that has to be re-sent on timeout

  public:
    Ingress_Router();
    virtual ~Ingress_Router();

  protected:
    virtual cMessage *generateNewMessage();
    virtual void sendCopyOf(cMessage *msg);
    virtual void initialize();
    virtual void handleMessage(cMessage *msg);
};

Define_Module(Ingress_Router);

Ingress_Router::Ingress_Router()
{
    timeoutEvent = message = NULL;
}

Ingress_Router::~Ingress_Router()
{
    cancelAndDelete(timeoutEvent);
    delete message;
}

void Ingress_Router::initialize()
{
    // Initialize variables.
    seq = 0;
    timeout = 1.0;
    timeoutEvent = new cMessage("timeoutEvent");

    // Generate and send initial message.
    EV << "Sending initial message\n";
    message = generateNewMessage();
    sendCopyOf(message);
    scheduleAt(simTime()+timeout, timeoutEvent);
}

void Ingress_Router::handleMessage(cMessage *msg)
{
    if (msg==timeoutEvent)
    {
        // If we receive the timeout event, that means the packet hasn't
        // arrived in time and we have to re-send it.
        EV << "Timeout expired, resending message and restarting timer\n";
        sendCopyOf(message);
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
    else // message arrived
    {
        // Acknowledgement received!
        EV << "Received: " << msg->getName() << "\n";
        delete msg;

        // Also delete the stored message and cancel the timeout event.
        EV << "Timer cancelled.\n";
        cancelEvent(timeoutEvent);
        delete message;

        // Ready to send another one.
        message = generateNewMessage();
        sendCopyOf(message);
        scheduleAt(simTime()+timeout, timeoutEvent);
    }
}

cMessage *Ingress_Router::generateNewMessage()
{
    // Generate a message with a different name every time.
    char msgname[20];
    sprintf(msgname, "tic-%d", ++seq);
    cMessage *msg = new cMessage(msgname);
    return msg;
}

void Ingress_Router::sendCopyOf(cMessage *msg)
{
    // Duplicate message and send the copy.
    cMessage *copy = (cMessage *) msg->dup();
    //send(copy, "gate");
    // Same routing as before: random gate.
    int n = gateSize("gate");
    int k = intuniform(0,n-1);
    send(copy, "gate$o", 0);
}



class Ergress_Router : public cSimpleModule
{
  protected:
    virtual void handleMessage(cMessage *msg);
};

Define_Module(Ergress_Router);

void Ergress_Router::handleMessage(cMessage *msg)
{
    if (uniform(0,1) < 0.1)
    {
        EV << "\"Losing\" message " << msg << endl;
        bubble("message lost");
        delete msg;
    }
    else
    {
        EV << msg << " received, sending back an acknowledgement.\n";
        delete msg;
       // send(new cMessage("ack"), "gate");
    }
}

class Core_Router : public cSimpleModule
{
  protected:
    virtual void handleMessage(cMessage *msg);
};

Define_Module(Core_Router);

void Core_Router::handleMessage(cMessage *msg)
{
    if (uniform(0,1) < 0.1)
    {
        EV << "\"Losing\" message " << msg << endl;
        bubble("message lost");
        delete msg;
    }
    else
    {
        EV << msg << " received, sending back an acknowledgement.\n";
        delete msg;

       // send(new cMessage("ack"), "gate$o", 1);
       // send(new cMessage("ack"), "gate$o", 0);
    }
}

